package com.dingwen.treasure.kettle.config;

import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.RequestHandler;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;

import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * 　Knife4jConfiguration
 * knife4j配置: 切接使用{@link @ConfigurationProperties } 必须生成 get set 方法
 * 　@author dingwen
 * 　@date 2022/6/11
 */
@Configuration(proxyBeanMethods = false)
@EnableSwagger2WebMvc
@ConfigurationProperties(prefix = "knife4j")
@Setter
@Getter
public class Knife4jConfiguration {


    /**
     * 定义分隔符
     */
    private static final String SEPARATOR = ":";

    /**
     * 标题
     */
    private String title = StringUtils.EMPTY;
    /**
     * 描述
     */
    private String description = StringUtils.EMPTY;
    /**
     * 服务地址
     */
    private String termsOfServiceUrl = StringUtils.EMPTY;
    /**
     * 版本号
     */
    private String version = StringUtils.EMPTY;
    /**
     * 分组名称
     */
    private String groupName = StringUtils.EMPTY;
    /**
     * 接口包路径
     */
    private String basePackage = StringUtils.EMPTY;

    /**
     * 联系人信息
     */
    private MyContact contact;

    /**
     * 必须是静态内部类才能注入成功
     *
     * @author dingwen
     * @date 2022/06/03
     */
    @Getter
    @Setter
    public static class MyContact {
        private String name;
        private String url;
        private String email;
    }

    @Bean(value = "defaultApi2")
    public Docket defaultApi2() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(new ApiInfoBuilder()
                        .title(title)
                        .description(description)
                        .termsOfServiceUrl(termsOfServiceUrl)
                        .contact(new Contact(contact.getName(), contact.getUrl(), contact.getEmail()))
                        .version(version)
                        .build())
                //分组名称
                .groupName(groupName)
                .select()
                //这里指定Controller扫描包路径
                .apis(basePackage(basePackage))
                .paths(PathSelectors.any())
                .build();
    }


    /**
     * @param basePackage 所有包路径
     * @return Predicate<RequestHandler>
     * @author luoyu
     * @description 重写basePackage方法，使能够实现多包访问
     */
    public static Predicate<RequestHandler> basePackage(final String basePackage) {
        return input -> declaringClass(input).map(handlerPackage(basePackage)).orElse(true);
    }

    /**
     * @param basePackage 所有包路径
     * @return Function<Class < ?>, Boolean>
     * @author luoyu
     * @description 重写basePackage方法，使能够实现多包访问
     */
    private static Function<Class<?>, Boolean> handlerPackage(final String basePackage) {
        return input -> {
            // 循环判断匹配
            for (String strPackage : basePackage.split(SEPARATOR)) {
                assert input != null;
                boolean isMatch = input.getPackage().getName().startsWith(strPackage);
                if (isMatch) {
                    return true;
                }
            }
            return false;
        };
    }

    /**
     * @param input
     * @return Optional<? extends Class < ?>>
     * @author luoyu
     * @description 重写basePackage方法，使能够实现多包访问
     */
    private static Optional<Class<?>> declaringClass(RequestHandler input) {
        return Optional.ofNullable(input.declaringClass());
    }
}
